import {
  htmlStringToElement,
  updateWatcher,
  bindProperties,
  deepAttributeInObject,
  getDataType,
} from './utils/index.js'
import LveProxy from './proxy.js'
import {
  parse
} from './replace.js'

class Component {
  constructor(propsArgus = {}) {
    const {
      data = () => {},
      methods = {},
      watch = {},
      computed = {}, // 待实现
      props = {}, // 待实现
      created = () => {}, // created钩子函数
      mounted = () => {}, // mounted钩子函数
      destroyed = () => {} // destroyed钩子函数
    } = propsArgus
    this.$watch = watch // watch方法集合
    this.$watchers = {} // 收集器集合
    this.$methods = methods // 执行方法集合
    this.$data = data() || {} // 数据定义集合
    this.$computed = computed // 计算属性集合 待开发
    this.$props = props // 传递属性集合
    this.$created = created // created生命周期注入
    this.$mounted = mounted // mounted生命周期注入
    this.$destroyed = destroyed // destroyed生命周期注入
    bindProperties(this, this.$data)
    this.observe(this)
    bindProperties(this, this.$methods)
    this.$created() // created钩子执行 在dom挂载之前执行
  }
  /**
   * 转换观测模式
   * @param {*} data 当前作用指针
   * @returns 
   */
  observe (data) {
    if (!data || getDataType(data) !== 'object') { // 按顺序写一般都不会进入这一步 用于初始化
      return
    }
    const arrayMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort']
    const keys = Object.keys(this.$data)
    for (let key of keys) {
      let value = data[key]
      if (getDataType(value) === 'object' ||
          getDataType(value) === 'array' ||
          getDataType(value) === 'null'
        ) {
        value = getDataType(value) === 'null' ? {} : value // Proxy不能传入不是对象的类型，所以在这里转一下
        data[key] = this.deepProxy(key, value)
      } else {
        Object.defineProperty(data, key, {
          configurable: false,
          enumerable: true,
          set(val) {
            value = val
            updateWatcher(this.$watchers[key], val) // 数据改变 watcher触发修改对应界面上的值
            if (data.$watch[key]) {
              data.$watch[key].call(data, val) // 主动触发watch对象的方法
            } 
          },
          get() {
            return value
          }
        })
      }
    }
  }
  /**
   * 深度遍历并转换为自定义Proxy代理
   * @param {*} obj 
   * @returns
   */
  deepProxy(key, obj) {
    if (getDataType(obj) === 'array') { // 数组深度遍历
      obj.forEach((v, i) => {
        if (getDataType(obj) === 'object') {
          obj[i] = this.deepProxy(v)
        }
      })
    } else  { // 对象深度遍历
      if (Object.keys(obj).length === 0) return
      Object.keys(obj).forEach(v => {
        if (getDataType(obj[v]) === 'object') {
          obj[v] = this.deepProxy(key, obj[v])
        }
      });
    }
    const proxy = new LveProxy(this, obj).init(key) // proxy代理
    return proxy
  }
  /**
   * 将组件实例挂载到指定dom上
   */
  mount(domName) {
    const dom = document.querySelector(domName)
    parse(dom, this)
    window.onload = () => { // 全局都在onload后执行，不需要nextTick了
      this.$mounted() // mounted钩子执行
    };
    window.onunload = () => {
      this.$destroyed() // destroyed钩子执行 目前只在页面刷新时执行
    }
  }
}

export {
  Component
}